/*
 * Created on Mar 3, 2010
 */
package com.mgmaps.tools;

import javax.microedition.lcdui.*;

public class UITools {

  private UITools() {
  }
  
  
  /**
   * Delete all elements in a list, compatibility with MIDP 1.0.
   * @param l list to process
   */
  public static void deleteAll(List l) {
    // select the first element
    if (l.size() > 0)
      l.setSelectedIndex(0, true);
    
    l.deleteAll();
  }
  
  
  /**
   * Build a form.
   * 
   * @param title form title
   * @param items form items
   * @param cmds commands for the form
   * @param lsn command listener
   * @return the form
   */
  public static final Form buildForm(Form oldForm, String title, Item[] items, Command[] cmds, CommandListener lsn) {
    if (oldForm != null)
      oldForm.deleteAll();
    Form form = new Form(title, items);
    for (int i=0; i<cmds.length; i++)
      form.addCommand(cmds[i]);
    form.setCommandListener(lsn);
    return form;
  }
  
  
  /**
   * Build a list.
   * 
   * @param title list title
   * @param items list items (strings)
   * @param images list items (images)
   * @param cmds commands for the list
   * @param lsn command listener
   * @return the list
   */
  public static final List buildList(List oldList, String title, String[] items, Image[] images, Command selectCmd, Command[] cmds, CommandListener lsn) {
    if (oldList != null)
      deleteAll(oldList);
    List list = new List(title, List.IMPLICIT, items, images);
    if (selectCmd != null)
      list.setSelectCommand(selectCmd);
    for (int i=0; i<cmds.length; i++)
      list.addCommand(cmds[i]);
    list.setCommandListener(lsn);
    return list;
  }

  
  /**
   * Build a form, no commands.
   * 
   * @param title form title
   * @param items form items
   * @return the form
   */
  public static final Form buildForm(Form oldForm, String title, Item[] items) {
    if (oldForm != null)
      oldForm.deleteAll();
    Form form = new Form(title, items);
    return form;
  }
  
  
  /**
   * Scale an image down 2^n times.
   * @param src image to scale
   * @param dif logarithmic scaling level (1 = scale by 2, 2 = scale by 4, etc.)
   * @return the scaled image
   */
  public static Image scaleImage05(Image src, int dif) {
    final int srcWidth = src.getWidth();
    final int srcHeight = src.getHeight();
    final int dstWidth = srcWidth >> dif;
    final int dstHeight = srcHeight >> dif;
    final Image dst = Image.createImage(dstWidth, dstHeight);
    final Graphics g = dst.getGraphics();
    final int[] lineRGB = new int[srcWidth];
    final int[] srcPos = new int[dstWidth]; // cache for x positions
    
    /*
     * Pre-calculate x positions with modified bresenham algorithm
     * http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
     */
    for (int x = 1; x < dstWidth; x++)
      srcPos[x] = (x<<dif);

    for (int y = 0; y < dstHeight; y++) {
      src.getRGB(lineRGB, 0, srcWidth, 0, y<<dif, srcWidth, 1);
      for (int x = 1; x < dstWidth; x++) // skip pixel 0
        lineRGB[x] = lineRGB[srcPos[x]];
      g.drawRGB (lineRGB, 0, dstWidth, 0, y, dstWidth, 1, false);
    }
    
    return dst;
  }

  
  /**
   * Scale an image up 2^n times.
   * @param image image to scale
   * @param dif logarithmic scaling level (1 = scale by 2, 2 = scale by 4, etc.)
   * @return the scaled image
   */
  public static Image scaleImage20(Image src, int dif) {
    final int dstWidth = src.getWidth();
    final int dstHeight = src.getHeight();
    int srcWidth = dstWidth >> dif;
    int srcHeight = dstHeight >> dif;
    if (srcWidth < 1)
      srcWidth = 1;
    if (srcHeight < 1)
      srcHeight = 1;
    final int srcX = (dstWidth-srcWidth) >> 1;
    final int srcY = (dstHeight-srcHeight) >> 1;
    final Image dst = Image.createImage(dstWidth, dstHeight);
    final Graphics g = dst.getGraphics();
    final int[] lineRGB = new int[dstWidth];
    final int[] srcPos = new int[dstWidth]; // cache for x positions
    final int[] lineRGB2 = new int[dstWidth];
    
    /*
     * Pre-calculate x positions with modified bresenham algorithm
     * http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
     */
    for (int x = 0; x < dstWidth; x++)
      srcPos[x] = srcX+(x>>dif);

    for (int y = 0; y < dstHeight; y++) {
      src.getRGB(lineRGB, 0, dstWidth, 0, srcY+(y>>dif), dstWidth, 1);
      for (int x = 0; x < dstWidth; x++)
        lineRGB2[x] = lineRGB[srcPos[x]];
      g.drawRGB (lineRGB2, 0, dstWidth, 0, y, dstWidth, 1, false);
    }
    
    return dst;
  }
  
  
  /**
   * Scale an image up 2 times.
   * @param image image to scale
   * @return the scaled image
   */
  public static Image scaleImage2x(Image src) {
    final int srcWidth = src.getWidth();
    final int srcHeight = src.getHeight();
    final int dstWidth = srcWidth << 1;
    final int dstHeight = srcHeight << 1;
    final Image dst = Image.createImage(dstWidth, dstHeight);
    final Graphics g = dst.getGraphics();
    final int[] lineRGB = new int[dstWidth];
    final int[] srcPos = new int[dstWidth]; // cache for x positions
    final int[] lineRGB2 = new int[dstWidth];
    
    /*
     * Pre-calculate x positions with modified bresenham algorithm
     * http://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html
     */
    for (int x = 0; x < dstWidth; x++)
      srcPos[x] = x>>1;

    for (int y = 0; y < dstHeight; y++) {
      src.getRGB(lineRGB, 0, srcWidth, 0, y>>1, srcWidth, 1);
      for (int x = 0; x < dstWidth; x++)
        lineRGB2[x] = lineRGB[srcPos[x]];
      g.drawRGB(lineRGB2, 0, dstWidth, 0, y, dstWidth, 1, false);
    }
    
    return dst;
  }

  
  /**
   * Extract an icon from a bigger image. Keep transparency.
   *  
   * @param orig original image
   * @param total total number of icons stored (horizontally)
   * @param current index number of extracted icon
   * @return the extracted icon
   */
  public static Image extractImage(Image orig, int total, int current) {
    return extractImage(orig, orig.getWidth()/total, current, 0, orig.getHeight());
  }

  
  /**
   * Extract an icon from a bigger image. Keep transparency.
   *  
   * @param orig original image
   * @param w width of an icon
   * @param h height of an icon
   * @param y y-offset
   * @param current index number of extracted icon
   * @return the extracted icon
   */
  public static Image extractImage(Image orig, int w, int current, int y, int h) {
    // get RGB
    int[] rgbData = new int[h*w];
    orig.getRGB(rgbData, 0, w, current*w, y, w, h);
    // put RGB and create image
    return Image.createRGBImage(rgbData, w, h, true);
  }

  
  /**
   * Extract an image from a bigger image. Does not keep transparency. 
   * @param image image to process
   * @param x x
   * @param y y
   * @param w width
   * @param h height
   * @return the cropped image
   */
  public static Image cropImage(Image image, int x, int y, int w, int h) {
    // create a temp image
    Image cropped = Image.createImage(w, h);
    Graphics g = cropped.getGraphics();
    g.drawImage(image, -x, -y, Graphics.TOP | Graphics.LEFT);
    // make it immutable
    // MIDP specs mention that all images used as icons for list, etc. should be immutable 
    return Image.createImage(cropped);
  }
  
  
  /**
   * Check that the int value in a TextField is in a given range.
   * 
   * @param fld TextField object
   * @param min lower bound
   * @param max upper bound
   * @return true if it's in that range, false if not or if it's not a number
   */
  public static boolean checkIntField(TextField fld, int min, int max, boolean isZoom) {
    try {
      // get value
      int value = Integer.parseInt(fld.getString());
      if (isZoom)
        value = 17-value;
      if (value < min || value > max)
        return false;
    }
    catch (NumberFormatException nfe) {
      // number exception, return false
      return false;
    }
    
    // otherwise return true
    return true;
  }
}
